#ifndef RT_H_
#define RT_H_

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

enum
{
  MC_EVENT_COUNT_LOG2 = 6,
  MC_EVENT_COUNT = (1 < MC_EVENT_COUNT_LOG2),
  MC_EVENT_MASK = (MC_EVENT_COUNT - 1),

  MC_IO_BUF = 1024 * 1024,
};

struct runtime;

enum event_type
{
  EVENT_OPEN,
  EVENT_CREATE,
  EVENT_READ,
  EVENT_WRITE,
  EVENT_CLOSE,
};

struct task_ctx;
typedef bool (*func_task) (struct runtime *, struct task_ctx *);

struct task
{
  func_task task;
  struct task_ctx *ctx;
};

struct ev_open
{
  char const *path;
  func_task on_ok;
  func_task on_error;
};

struct ev_read
{
  FILE *fp;
  func_task on_ok;
  func_task on_error;
  func_task on_eof;
};

struct ev_write
{
  FILE *fp;
  func_task on_ok;
  func_task on_error;
};

struct ev_close
{
  FILE *fp;
  func_task then;
};

struct event
{
  enum event_type type;

  union
  {
    struct ev_open open;
    struct ev_read read;
    struct ev_write write;
    struct ev_close close;
  } via;

  struct event *next;
};

struct runtime
{
  struct event events[MC_EVENT_COUNT];
  uint64_t event_begin;
  uint64_t event_end;

  // Arguments to events.
  FILE *fp;
  char iobuf[MC_IO_BUF];
  uint64_t iolen;
};

static inline void
rt_open (struct runtime *rt, struct ev_open ev)
{
  rt->events[(rt->event_end++) & MC_EVENT_MASK] = (struct event){
    .type = EVENT_OPEN,
    .via.open = ev,
  };
}

static inline void
rt_read (struct runtime *rt, struct ev_read ev)
{
  rt->events[(rt->event_end++) & MC_EVENT_MASK] = (struct event){
    .type = EVENT_READ,
    .via.read = ev,
  };
}

static inline void
rt_close (struct runtime *rt, struct ev_close ev)
{
  rt->events[(rt->event_end++) & MC_EVENT_MASK] = (struct event){
    .type = EVENT_CLOSE,
    .via.close = ev,
  };
}

static inline struct runtime
rt_make_runtime (void)
{
  return (struct runtime){
    .event_begin = 0,
    .event_end = 0,
  };
}

void rt_run (struct runtime *rt, func_task start, struct task_ctx *ctx);

#endif
